﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using MeshToolkit.PolygonCuttingEar;

namespace MeshToolkit
{
    public class MeshForClosedRegion
    {
        //对点的Y进行上下翻转（用于将提取自图像的点转换为Unity坐标系中的点）
        public static void FlipPoint_Y(List<Vector3> oEdgePoints)
        {
            float dMin = float.MaxValue;
            float dMax = float.MinValue;
            for (int i = 0; i < oEdgePoints.Count; i++)
            {
                if (oEdgePoints[i].y > dMax)
                {
                    dMax = oEdgePoints[i].y;
                }
                if (oEdgePoints[i].y < dMin)
                {
                    dMin = oEdgePoints[i].y;
                }
            }

            float dHeight = dMax + dMin;
            for (int i = 0; i < oEdgePoints.Count; i++)
            {
                oEdgePoints[i] = new Vector3(oEdgePoints[i].x, dHeight - oEdgePoints[i].y, oEdgePoints[i].z);
            }
        }

        public static MeshDraft EarTriangle(List<Vector2> oEdgePoints, bool bImageCoordinateSystem)
        {
            CPoint2D[] oPoints = new CPoint2D[oEdgePoints.Count];
            for (int i = 0; i < oEdgePoints.Count; i++)
            {
                oPoints[i] = new CPoint2D(oEdgePoints[i].x, oEdgePoints[i].y);
            }

            //耳切法三角拆分（图像坐标系，右手坐标系，三角形为逆时针）
            CPolygonShape oCutPolygon = new CPolygonShape(oPoints);
            oCutPolygon.CutEar();


            List<Vector3> oVertices = new List<Vector3>(oEdgePoints.Count);
            for (var i = 0; i < oEdgePoints.Count; i++)
            {
                oVertices.Add(new Vector3(oEdgePoints[i].x, oEdgePoints[i].y, 0));
            }
            List<int> oTriangles = oCutPolygon.GetTriangles();
            //来自图像坐标系的点，翻转Y轴后才能使Mesh的形状与图像中的边缘一致
            //耳切法返回的三角形是逆时针的，需要调整三角面片的顶点顺序使其保持顺时针
            if (bImageCoordinateSystem)
            {
                FlipPoint_Y(oVertices);
                for (int i = 0; i < oTriangles.Count; i += 3)
                {
                    int nTmp = oTriangles[i + 1];
                    oTriangles[i + 1] = oTriangles[i + 2];
                    oTriangles[i + 2] = nTmp;
                }
            }            

            var oDraft = new MeshDraft
            {
                vertices = oVertices,
                triangles = oTriangles,
                normals = new List<Vector3>(oVertices.Count),
                uv = new List<Vector2>(oVertices.Count),
                name = "TriangleEar"
            };

            var normal = Vector3.Cross(oVertices[oTriangles[1]] - oVertices[oTriangles[0]],
                oVertices[oTriangles[2]] - oVertices[oTriangles[0]]).normalized;
            for (int i = 0; i < oVertices.Count; i++)
            {
                oDraft.normals.Add(normal);
                oDraft.uv.Add(new Vector2((float)i / oVertices.Count, (float)i / oVertices.Count));
            }
            return oDraft;
        }

        public static Mesh PlaneMesh(List<Vector2> oEdgePoints, float dScale)
        {
            if (oEdgePoints.Count < 3)
            {
                throw new ArgumentNullException("oEdgePoints");
            }

            var oDraft = new MeshDraft { name = "PlaneMesh" };
            oDraft.Add(EarTriangle(oEdgePoints, true));
            oDraft.Scale(dScale);

            return oDraft.ToMesh();
        }

        public static Mesh CyliderMesh(List<Vector2> oEdgePoints, float dHeight, float dScale)
        {
            if (oEdgePoints.Count < 3)
            {
                throw new ArgumentNullException("oEdgePoints");
                return null;
            }

            var oDraft = new MeshDraft { name = "CyliderMesh"};
            
            //前面
            MeshDraft oPlaneMesh = EarTriangle(oEdgePoints, true);
            var oLowerPlaneDraft = new MeshDraft();
            oLowerPlaneDraft.Add(oPlaneMesh);
            oLowerPlaneDraft.Move(new Vector3(0, 0, -dHeight / 2));
            oDraft.Add(oLowerPlaneDraft);

            //后面
            var oUpperPlaneDraft = new MeshDraft();
            oUpperPlaneDraft.Add(oPlaneMesh);
            oUpperPlaneDraft.Move(new Vector3(0, 0, dHeight / 2));
            oUpperPlaneDraft.FlipFaces();
            oDraft.Add(oUpperPlaneDraft);

            //侧面
            var lowerRing = new List<Vector3>(oEdgePoints.Count);
            var upperRing = new List<Vector3>(oEdgePoints.Count);
            for (var i = 0; i < oEdgePoints.Count; i++)
            {
                lowerRing.Add(new Vector3(oEdgePoints[i].x, oEdgePoints[i].y, - dHeight / 2));
                upperRing.Add(new Vector3(oEdgePoints[i].x, oEdgePoints[i].y, dHeight / 2));
            }
            FlipPoint_Y(lowerRing);
            FlipPoint_Y(upperRing);
            oDraft.Add(MeshDraft.Band(upperRing,lowerRing));

            //缩放
            oDraft.Scale(dScale);

            return oDraft.ToMesh();
        }
    }
}

